﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace Team6_Algorithms.AidingClasses
{
    /// <summary>
    /// Class with a faster getPixel and setPixel.
    /// Made by Pascal Schotman
    /// </summary>
    class FastPixelAccess
    {
    private byte[] rgbValues;
    private BitmapData bmpData;
    private IntPtr bmpPtr;

    private Bitmap bitmap;
    private int height;
    private int width;

    private bool locked = false;
    private bool alpha = false;

    //constructor to load bitmap in class
    public FastPixelAccess(Bitmap bitmap)
    {
        this.bitmap = bitmap;
        this.alpha = (this.Bitmap.PixelFormat == (this.Bitmap.PixelFormat | PixelFormat.Alpha));
        this.width = bitmap.Width;
        this.height = bitmap.Height;
    }

        /// <summary>
        /// Lock the bitmap
        /// </summary>
    public void Lock()
    {
        //is bmp locked?
        if (this.locked)
            throw new Exception("Bitmap already locked.");
        
        //not locked
        Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
        this.bmpData = this.Bitmap.LockBits(rect, ImageLockMode.ReadWrite, this.Bitmap.PixelFormat);
        this.bmpPtr = this.bmpData.Scan0;

        //alpha?
        if (this.IsAlphaBitmap)
        {
            int bytes = (this.Width * this.Height) * 4;
            this.rgbValues = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length);
        }
        else
        {
            int bytes = (this.Width * this.Height) * 3;
            this.rgbValues = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length);
        }
        this.locked = true;
    }
        /// <summary>
        /// Unlock the bitmap
        /// </summary>
        /// <param name="setPixels"></param>
    public void Unlock(bool setPixels)
    {
        //is bmp locked?
        if (!this.locked)
            throw new Exception("Bitmap not locked.");

        // Copy the RGB values back to the bitmap;
        if (setPixels)
            System.Runtime.InteropServices.Marshal.Copy(this.rgbValues, 0, this.bmpPtr, this.rgbValues.Length);

        // Unlock the bits.;
        this.Bitmap.UnlockBits(bmpData);
        this.locked = false;
    }
        /// <summary>
        /// Sets a pixel to a specific color
        /// </summary>
        /// <param name="x">x-position</param>
        /// <param name="y">y-position</param>
        /// <param name="color">color to set the pixel to.</param>
    public void SetPixel(int x, int y, Color color)
    {
        //is bmp locked?
        if (!this.locked)
            throw new Exception("Bitmap not locked.");

        //alpha?
        if (this.IsAlphaBitmap)
        {
            int index = ((y * this.Width + x) * 4);
            this.rgbValues[index] = color.B;
            this.rgbValues[index + 1] = color.G;
            this.rgbValues[index + 2] = color.R;
            this.rgbValues[index + 3] = color.A;
        }
        else
        {
            int index = ((y * this.Width + x) * 3);
            this.rgbValues[index] = color.B;
            this.rgbValues[index + 1] = color.G;
            this.rgbValues[index + 2] = color.R;
        }
    }
        
    /// <summary>
    /// Gets the color of a specific pixel
    /// </summary>
    /// <param name="x">x-position</param>
    /// <param name="y">y-position</param>
    /// <returns>the color of the selected pixel</returns>
    public Color GetPixel(int x, int y)
    {
        //is bmp locked?
        if (!this.locked)
            throw new Exception("Bitmap not locked.");

        //alpha?
        if (this.IsAlphaBitmap)
        {
            int index = ((y * this.Width + x) * 4);
            int b = this.rgbValues[index];
            int g = this.rgbValues[index + 1];
            int r = this.rgbValues[index + 2];
            int a = this.rgbValues[index + 3];
            return Color.FromArgb(a, r, g, b);
        }
        else
        {
            int index = ((y * this.Width + x) * 3);
            int b = this.rgbValues[index];
            int g = this.rgbValues[index + 1];
            int r = this.rgbValues[index + 2];
            return Color.FromArgb(r, g, b);
        }
    }
    public int Width
    {
        get
        {
            return this.width;
        }
    }

    public int Height
    {
        get
        {
            return this.height;
        }
    }

    public bool IsAlphaBitmap
    {
        get
        {
            return this.alpha;
        }
    }

    public Bitmap Bitmap
    {
        get
        {
            return this.bitmap;
        }
    }
}
    
}
